﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Vector2 = DDD.Vector2<float>;
using Vector3 = DDD.Vector3<float>;


namespace DDD {
    /// <summary>
    /// ポイントスプライトの見え方を制御するアピアランスの構成要素
    /// </summary>
    /// <remarks>
    /// このクラスはポイントスプライトの見え方を制御するアピアランスの構成要素の1つです。
    /// <see cref="PrimitiveType.Point"/>を持つ<see cref="IndexBuffer"/>と同時に使用されたときのみ意味を持ちます。
    /// </remarks>
    public class PointSpriteMode : Object {
        #region Field
        float constantAttenuation;
        float linearAttenuation;
        float quadraticAttenuation;
        float alphaThreshold;
        float clampMin;
        float clampMax;
        #endregion

        #region Constructor
        /// <summary>
        /// コンストラクター
        /// </summary>
        public PointSpriteMode () {
            this.constantAttenuation = 1;
            this.linearAttenuation = 0;
            this.quadraticAttenuation = 0;
            this.alphaThreshold = 0;
            this.clampMin = 0;
            this.clampMax = 0;
        }
        #endregion

        #region Property

        /// <summary>
        /// 減衰定数
        /// </summary>
        public Vector3 Attenuation {
            get { return new Vector3 (constantAttenuation, linearAttenuation, quadraticAttenuation); }
            private set {
                this.constantAttenuation = value[0];
                this.linearAttenuation = value[1];
                this.quadraticAttenuation = value[2];
            }
        }

        /// <summary>
        /// 定数減衰定数
        /// </summary>
        public float ConstantAttenuation {
            get { return constantAttenuation; }
            private set { this.constantAttenuation = value; }
        }

        /// <summary>
        /// 線形減衰定数
        /// </summary>
        public float LinearAttenuation {
            get { return linearAttenuation; }
            private set { this.linearAttenuation = value; }
        }

        /// <summary>
        /// 2次減衰定数
        /// </summary>
        public float QuadraticAttenuation {
            get { return quadraticAttenuation; }
            private set { this.quadraticAttenuation = value; }
        }

        /// <summary>
        /// αフェードの閾値
        /// </summary>
        /// <remarks>
        /// この閾値を下回ると描画されなくなります。
        /// </remarks>
        public float AlphaThreshold {
            get { return alphaThreshold; }
            private set { this.alphaThreshold = value; }
        }

        /// <summary>
        /// ポイントサイズの上限と下限
        /// </summary>
        public Vector2 ClampSize {
            get { return new Vector2 (clampMin, clampMax); }
            private set {
                this.clampMin = value[0];
                this.clampMax = value[1];
            }
        }

        /// <summary>
        /// ポイントサイズの下限
        /// </summary>
        /// <remarks>
        /// このポイントスプライトはこのサイズにクランプされます。
        /// </remarks>
        public float ClampMin {
            get { return clampMin; }
            private set { this.clampMin = value; }
        }

        /// <summary>
        /// ポイントサイズの上限
        /// </summary>
        /// <remarks>
        /// ポイントスプライトはこのサイズにクランプされます。
        /// </remarks>
        public float ClampMax {
            get { return clampMax; }
            private set { this.clampMax = value; }
        }

        /// <summary>
        /// このオブジェクトが参照する全DDDオブジェクトを列挙する列挙子
        /// </summary>
        /// <remarks>
        /// 参照にnullは含まれません。同一のオブジェクトが複数出現する可能性があります。
        /// </remarks>
        public override IEnumerable<Object> References {
            get {
                return base.References;
            }
        }
        #endregion

        #region Method

        /// <summary>
        /// 減衰定数を設定します
        /// </summary>
        /// <param name="c">定数係数</param>
        /// <param name="l">線形係数</param>
        /// <param name="q">2次係数</param>
        public void SetAttenuation (float c, float l, float q) {
            if (c == 0 && l == 0 && q == 0) {
                throw new ArgumentException ("All 0 attenuation is invalid");
            }
            this.constantAttenuation = c;
            this.linearAttenuation = l;
            this.quadraticAttenuation = q;
        }

        /// <summary>
        /// クランプサイズを設定します
        /// </summary>
        /// <param name="min">下限</param>
        /// <param name="max">上限</param>
        public void SetClampSize (float min, float max) {
            if (min > max) {
                throw new ArgumentException ("Min,Max is invalid");
            }
            this.clampMin = min;
            this.clampMax = max;
        }

        /// <summary>
        /// α閾値を設定します
        /// </summary>
        /// <remarks>
        /// この閾値以下のαを持つポイントスプライトは描画されません
        /// </remarks>
        /// <param name="alpha">閾値</param>
        public void SetAlphaThreshold (float alpha) {
            if (alpha < 0 || alpha > 1) {
                throw new ArgumentException ("Alpha threshold is invalid");
            }
            this.alphaThreshold = alpha;
        }

        /// <summary>
        /// 現在のオブジェクトの状態を表す文字列を返します。
        /// </summary>
        /// <returns>現在のオブジェクトを説明する文字列</returns>
        public override string ToString () {
            return string.Format ("PointSpriteMode: Attenuation={0},{1},{2}, threshold={3}, clamp={4},{5}"
                , ConstantAttenuation, LinearAttenuation, QuadraticAttenuation, AlphaThreshold, ClampMin, ClampMax);
        }
        #endregion
    }
}
